package org.agora.games.bodybuilder.ui;

import org.agora.games.bodybuilder.ImagePanel;
import org.agora.games.bodybuilder.Triangularizer;
import org.agora.games.bodybuilder.geometry.FixtureDefinition;
import org.agora.games.bodybuilder.geometry.mcd.CompGeom.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import outline.forweb.ImageOutlineFinder;
import svg.parser.Vertex;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * @author : Arash Bizhanzadeh <arashbi@gmail.ca>
 *         Date: 12-01-02
 *         Time: 2:34 PM
 *         CBC.ca All rights reserved.
 */
public class MainForm extends JFrame {
    public static Color[] COLORS = new Color[]{
            new Color(255,0,0),
            new Color(0,255,0),
            new Color(0,0,255),
            new Color(125,125,0)
    };
    public static Logger logger = LoggerFactory.getLogger(MainForm.class);
    private String fileName;
    private ImagePanel imagePanel;
    private JPanel centerPanel;
    private JPanel infoPanel;
    private JButton calculateButton;
    private JMenuBar menuBar;
    ImageOutlineFinder finder;
    private String average;
    private String maximumCurvature;
    private DecompPoly dp;
    private ArrayList<Vertex> vertexes;
    public static MainForm instance;

    public MainForm() {
         dp = new DecompPoly();
        instance = this;
        average = String.valueOf(3);
        maximumCurvature = String.valueOf(3);
        setLayout(new BorderLayout());
        setTitle("Simple example");
        setSize(800, 800);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        buildMenu();
        setJMenuBar(menuBar);

        infoPanel = new JPanel();
        centerPanel = new JPanel();
        infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.X_AXIS));
        add(infoPanel, BorderLayout.PAGE_END);
        add(centerPanel, BorderLayout.CENTER);

        imagePanel = new ImagePanel();
        centerPanel.setLayout(new BorderLayout());
        JScrollPane scrollableImage = new JScrollPane(imagePanel);
        centerPanel.add(scrollableImage, BorderLayout.CENTER);
        scrollableImage.setPreferredSize(scrollableImage.getParent().getSize());

        calculateButton = new JButton("Calculate");
//        calculateButton.setPreferredSize(new Dimension(100, Integer.MAX_VALUE));
        calculateButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                calculate();
            }
        });
        infoPanel.add(calculateButton);

        JButton showParams = new JButton("Show Params");
        showParams.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                   new Parameters(MainForm.this,true, average,maximumCurvature);

            }
        });

        infoPanel.add(showParams);


        addZoomSlider();
        finder= new ImageOutlineFinder();
    }

    private void addZoomSlider() {
        final JSlider zoomSlider = new JSlider();
        zoomSlider.setOrientation(JSlider.HORIZONTAL);
        zoomSlider.setMaximum(40);
        zoomSlider.setMinimum(1);
        zoomSlider.setValue(10);
        infoPanel.add(zoomSlider);
        zoomSlider.setPaintTicks(true);
        zoomSlider.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent changeEvent) {
                imagePanel.setZoom(zoomSlider.getValue() / 10f);
            }
        });
    }

    private void calculate() {
        if(finder.getImage() == null ||
                !finder.getImage().equals(fileName)){
            //todo alert the user;
            finder.setImage(fileName);
        }
        finder.findBorder();
        finder.average(Integer.valueOf(average));
         vertexes = finder.maximumCurvatureAlgorithm(Integer.valueOf(maximumCurvature));
        deCompose();
    }

    private void deCompose() {
        PointList pl = new PointList(vertexes.size());
        for (Vertex v : vertexes){
            pl.add((int)v.x,(int)v.y);
        }

        dp.setPoints(pl);
        List<List<DecompPoly.PP>> polygons = dp.calculate();

        List<FixtureDefinition> fixtures = new ArrayList<FixtureDefinition>();
        for(List<DecompPoly.PP> polygon : polygons){
            ArrayList<Vertex> vertexes1 = new ArrayList<Vertex>();
            vertexes1.add(vertexes.get(polygon.get(0).start));
            vertexes1.add(vertexes.get(polygon.get(0).end));
            for(int i = 1; i< polygon.size()-1; i++){
                vertexes1.add(vertexes.get(polygon.get(i).end));
            }
            FixtureDefinition f = new Triangularizer(vertexes1).calculate();
            f.setColor(COLORS[polygons.indexOf(polygon) % COLORS.length]);
            fixtures.add(f);
        }

        imagePanel.setFixtures(fixtures);
        imagePanel.revalidate();
        centerPanel.repaint();
    }

    private void loadImage() {
        JFileChooser ch = new JFileChooser();
        FileFilter fileFilter = new FileFilter() {
            @Override
            public boolean accept(File file) {
                try {
                    if (file.isFile() && file.getCanonicalPath().endsWith(".png")) {
                        return true;
                    }

                } catch (IOException e) {
                    logger.error("${MESSAGE}", e);
                }
                return false;
            }

            @Override
            public String getDescription() {
                return null;  //To change body of implemented methods use File | Settings | File Templates.
            }
        };
        ch.setFileFilter(fileFilter);
        int r = ch.showOpenDialog(this);
        if (r == JFileChooser.APPROVE_OPTION) {
            fileName = ch.getSelectedFile().toString();
            imagePanel.setImage(new File(fileName));
            imagePanel.repaint();
            centerPanel.revalidate();
        } else {
            logger.error("File is not accepted");
        }
    }

    private void buildMenu() {
        menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        JMenu actionMenu = new JMenu("Action");
        actionMenu.setMnemonic(KeyEvent.VK_A);
        fileMenu.setMnemonic(KeyEvent.VK_F);
        menuBar.add(fileMenu);
        menuBar.add(actionMenu);
        JMenuItem openMenu = new JMenuItem("Open");
        openMenu.setMnemonic(KeyEvent.VK_O);
        openMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK));
        fileMenu.add(openMenu);
        openMenu.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                loadImage();
            }
        });
        JMenuItem calculate = new JMenuItem("Calculate");
        calculate.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK));
        actionMenu.add(calculate);
        calculate.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                calculate();
            }
        });
        JMenuItem decomposeMenu = new JMenuItem("Decompose");
        actionMenu.add(decomposeMenu);
        decomposeMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyEvent.CTRL_DOWN_MASK));
        decomposeMenu.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                deCompose();
            }
        });
        JMenuItem saveMenu = new JMenuItem("Save");
        actionMenu.add(saveMenu);
        saveMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK));
        saveMenu.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                save();
            }
        });

    }

    public void setAverage(String text) {
        average = text;
    }

    public void setMaximumCurvature(String text) {
        maximumCurvature = text;
        logger.debug("Maximum Curvature now is {}" , text);
    }

    public void save() {
        JFileChooser ch = new JFileChooser();
                FileFilter fileFilter = new FileFilter() {
                    @Override
                    public boolean accept(File file) {
                        return true;
                    }
        
                    @Override
                    public String getDescription() {
                        return null;  //To change body of implemented methods use File | Settings | File Templates.
                    }
                };
                ch.setFileFilter(fileFilter);
                int r = ch.showSaveDialog(this);
                if (r == JFileChooser.APPROVE_OPTION) {
        OutputStream out = null;
        try {
            out = new FileOutputStream(ch.getSelectedFile().toString());
            logger.debug("created the file");

            XMLOutputFactory factory = XMLOutputFactory.newInstance();
            XMLStreamWriter writer = factory.createXMLStreamWriter(out);
            writer.writeStartDocument("UTF-8", "1.0");
            writer.writeStartElement("body");
            writer.writeStartElement("fixtures");
            List<FixtureDefinition> fixtures = imagePanel.getFixtures();
            for(FixtureDefinition f : fixtures){
                writer.writeStartElement("fixture");
                writer.writeAttribute("restitution", String.valueOf(f.getRestitution()));
                writer.writeAttribute("density", String.valueOf(f.getDensity()));
                writer.writeAttribute("friction", String.valueOf(f.getFriction()));
                writer.writeStartElement("shape");
                writer.writeStartElement("center");
                writer.writeAttribute("x", String.valueOf((int)f.getCenter().x));
                writer.writeAttribute("y", String.valueOf((int)f.getCenter().y));
                writer.writeEndElement();
                for(Vertex v : f.getPerimeter()){
                    writer.writeStartElement("point");
                    writer.writeAttribute("x", String.valueOf((int)v.x));
                    writer.writeAttribute("y",String.valueOf((int)v.y));
                    writer.writeEndElement();
                }
                writer.writeEndElement();
            }
            writer.writeEndElement();
            writer.writeEndElement();
            out.flush();
            out.close();
        } catch (FileNotFoundException e) {
            logger.error("${MESSAGE}", e);
        } catch (XMLStreamException e) {
            logger.error("${MESSAGE}", e);
        } catch (IOException e) {
            logger.error("${MESSAGE}", e);
        }
                }


    }
}
